#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <json-c/json.h>
#include <mysql.h>

#define MAXBUF 1024

void show_error(MYSQL *mysql)
{
    printf("Error(%d) [%s] \"%s\"", mysql_errno(mysql),
           mysql_sqlstate(mysql),
           mysql_error(mysql));
    mysql_close(mysql);
    exit(-1);
}

int check_sn(char *sn, char* info){
    MYSQL *mysql;
    MYSQL_RES *result;
    char *query = (char*)malloc(sizeof(char)*1000);
    int has_sn, i_result = 0;

    //mysql_debug("d:t:O");
   
    mysql= mysql_init(NULL);
    
    if (!mysql_real_connect(mysql, "localhost", "root", "wtfuem", "zqb", 0, NULL, 0))
        show_error(mysql);
    
    sprintf(query, "SELECT * FROM kj where sn=%s", sn); //query= "SELECT * FROM kj where sn='ACPZ0FC206161'";
    printf("%s\n", query);

    if (mysql_real_query(mysql, query, strlen(query)))
        show_error(mysql);
    result= mysql_store_result(mysql);
    
    has_sn = (unsigned long) mysql_affected_rows(mysql);
    //printf("Affected_rows after SELECT and storing result set: %lu\n",has_sn);
    
    if (has_sn > 0){
        i_result = 1;
    }
    /* Affected rows with UPDATE statement */
    
    sprintf(query, "UPDATE kj SET info='%s' WHERE  sn=%s", info, sn);
    //printf(query);
    
    
    if (mysql_real_query(mysql, query, strlen(query)))
        show_error(mysql);
    //printf("Affected_rows after UPDATE: %lu\n", (unsigned long) mysql_affected_rows(mysql));

    free(query);
    mysql_free_result(result);
    mysql_close(mysql);

    return i_result;
}

int jsondecode(char* json, char* device_id, char* device_name, char* device_sn){


    json_object *result_object = json_tokener_parse(json);
    if(is_error(result_object) ) //正确
    {
        printf("oh, my god. json_tokener_parse err\n");
        return -1;
    }

    json_object *result_object1 = NULL;
    result_object =  json_object_object_get(result_object, "result");
    /*
    printf("-----------result_object method ---------------------------\n");
    printf("%s\n", json_object_to_json_string(result_object));
    printf("-----------result_object method---------------------------\n");
     */
    result_object =  json_object_array_get_idx(result_object, 1);
    result_object1 =  json_object_object_get(result_object, "device_id");
    strcpy(device_id, json_object_to_json_string(result_object1));

    //device_id =json_object_to_json_string(result_object1);
    //printf("-----------device_id method ---------------------------\n");
    //printf("%s\n", json_object_to_json_string(result_object1));
    //printf("-----------device_id method---------------------------\n");


    result_object1 =  json_object_object_get(result_object, "device_name");
    strcpy(device_name, json_object_to_json_string(result_object1));

    result_object1 =  json_object_object_get(result_object, "device_sn");
    strcpy(device_sn, json_object_to_json_string(result_object1));

    json_object_put(result_object);
    json_object_put(result_object1);
    return 1;
}


int jsonsend(SSL *ssl, char* buf){
    int len = 0;
    len = strlen(buf);
    len = htonl(len);
    len = SSL_write(ssl, &len, sizeof(len));

    if (len <= 0) {
        printf("消息first size: '%d'发送失败！错误代码是%d，错误信息是'%s'\n",strlen(buf), errno, strerror(errno));
        //goto finish;
        return -1;
    } else{
        printf("消息first size: '%d'发送成功，共发送了%d个字节！\n",strlen(buf), len);
    }


    len = SSL_write(ssl, buf, strlen(buf));
    if (len <= 0) {
        printf("消息'%s'发送失败！错误代码是%d，错误信息是'%s'\n\n",buf, errno, strerror(errno));
        //goto finish;
        return -1;
    } else{
        printf("消息'%s'发送成功，发送了%d字节！\n\n",buf, len);
    }

    return 1;

}

int jsonrecv(SSL *ssl, char* buf){

    int size = 0, len = 0;
    SSL_read(ssl, &size, sizeof(size));
    size = ntohl(size);
    if (size > 0x100000){
        printf("size error\n");
        return -1;
    }

    bzero(buf, MAXBUF + 1);
    len = SSL_read(ssl, buf, size);
    if (len <= 0) {
        printf("消息接受失败！错误代码是%d，错误信息是'%s'\n", errno, strerror(errno));
        return -1;
    }
    printf("接收成功:%s，共%d字节\n\n",buf, len);
    return 1;
}

int main(int argc, char **argv)
{
    fflush(stdout);
    setvbuf(stdout,NULL,_IONBF,0);
    
    int sockfd, new_fd, size = 0 ,len_send = 0, len;
    //socklen_t len;
    struct sockaddr_in my_addr, their_addr;
    unsigned int myport, lisnum;
    char buf[MAXBUF + 1] , device_id[64], device_sn[64], device_name[64],
            type[10], ip[32], netmask[32], gateway[32],dnstype[10];
    SSL_CTX *ctx;

    FILE* fp;
    fp=fopen("server.log","a");

    myport = atoi(argv[1]); //端口
    lisnum = atoi(argv[2]);//监听数量

    
    SSL_library_init();
    OpenSSL_add_all_algorithms();
    SSL_load_error_strings();
    ctx = SSL_CTX_new(SSLv23_server_method());
    if (ctx == NULL) {
        ERR_print_errors_fp(stdout);
        exit(1);
    }
    if (SSL_CTX_use_certificate_file(ctx, argv[4], SSL_FILETYPE_PEM) <= 0) {
        ERR_print_errors_fp(stdout);
        exit(1);
    }
    if (SSL_CTX_use_PrivateKey_file(ctx, argv[5], SSL_FILETYPE_PEM) <= 0) {
        ERR_print_errors_fp(stdout);
        exit(1);
    }
    if (!SSL_CTX_check_private_key(ctx)) {
        ERR_print_errors_fp(stdout);
        exit(1);
    }
    if ((sockfd = socket(PF_INET, SOCK_STREAM, 0)) == -1) {
        //perror("socket");
        exit(1);
    } else{
        //printf("socket created\n");
    }

    
    bzero(&my_addr, sizeof(my_addr));
    my_addr.sin_family = PF_INET;
    my_addr.sin_port = htons(myport);
    if (argv[3])
        my_addr.sin_addr.s_addr = inet_addr(argv[3]);
    else
        my_addr.sin_addr.s_addr = INADDR_ANY;
    
    if (bind(sockfd, (struct sockaddr *) &my_addr, sizeof(struct sockaddr))== -1) {
        //perror("bind");
        exit(1);
    } else{
        //printf("binded\n");
    }

    
    if (listen(sockfd, lisnum) == -1) {
        perror("listen");
        exit(1);
    } else
        printf("begin listen\n");
    
    while (1) {
        SSL *ssl;
        len = sizeof(struct sockaddr);
        
        if ((new_fd = accept(sockfd, (struct sockaddr *) &their_addr, &len)) == -1) {
            perror("accept");
            continue;
            //exit(errno);
        } else
            printf("server: got connection from %s, port %d, socket %d\n\n",inet_ntoa(their_addr.sin_addr),ntohs(their_addr.sin_port), new_fd);
        
        ssl = SSL_new(ctx);
        SSL_set_fd(ssl, new_fd);

        if (SSL_accept(ssl) == -1) {
            perror("accept");
            close(new_fd);
            continue;
            //break;//TODO
        }

        bzero(buf, MAXBUF + 1);
        sprintf(buf, "{\"jsonrpc\":\"2.0\",\"id\":0,\"method\":\"call\",\"params\":[\"\",\"remote\",\"get_profile\",{}]}");

        len = jsonsend(ssl, buf);
        if (len <= 0 ){
            goto finish;//发送失败
        }

        len = jsonrecv(ssl, buf);
        if (len <= 0 ){
            goto finish;//接受失败
        }

        len = jsondecode(buf, device_id, device_name, device_sn);
        if (len <= 0){
            printf("json解析失败");
            goto finish;
        }

        int has_device = check_sn(device_sn, buf);
        if (has_device){
            printf("数据库验证通过\n\n");
        }else{
            printf("数据库验证失败\n\n");

            fprintf(fp,"%s\n\n", buf);

            goto finish;
        }

        /////////////////////////////////////////////////////////////////////
        //发送密码
        bzero(buf, MAXBUF + 1);
        sprintf(buf, "{\"jsonrpc\":\"2.0\",\"id\":0,\"method\":\"call\",\"params\":[\"\",\"netcfg\",\"set_device_discovery\",{\"device_id\":%s,\"device_name\":%s,\"device_password\":\"12345678\"}]}", device_id, device_name);
        len = jsonsend(ssl, buf);
        if (len <= 0 ){
            //发送失败
            goto finish;
        }
        //发送密码
        /////////////////////////////////////////////////////////////////////

        /////////////////////////////////////////////////////////////////////
        //读取设置结果
        len = jsonrecv(ssl, buf);
        if (len <= 0 ){
            goto finish;//读取设置结果
        }
        //printf("接收设置结果成功:%s，共%d字节\n\n",buf, len);
        //读取设置结果
        /////////////////////////////////////////////////////////////////////

        finish:
        SSL_shutdown(ssl);
        SSL_free(ssl);
        close(new_fd);
    }
    close(sockfd);
    fclose(fp);
    SSL_CTX_free(ctx);
    return 0;
}